package pr.lanmu.service;

import com.mybatisflex.core.query.QueryChain;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import pr.lanmu.annotation.CustomLog;
import pr.lanmu.common.mapper.MenuMapper;
import pr.lanmu.common.po.Menu;
import pr.lanmu.config.util.ConvertUtil;
import pr.lanmu.config.util.Res;
import pr.lanmu.config.web.CustomException;
import pr.lanmu.controller.request.MenuReq;
import pr.lanmu.controller.response.MenuRes;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;


/**
 * 菜单服务
 */
@Service
@CustomLog
@SuppressWarnings("all")
public class MenuService {
    @Autowired
    private MenuMapper menuMapper;


    /**
     * 获取所有菜单
     *
     * @param param 菜单请求参数
     * @return 菜单列表
     */
    public Res<List<MenuRes.all>> all(MenuReq.all param) {
        List<Menu> list = new Menu()
                .orderBy(Menu::getSort, false)
                .list();
        return Res.success(getTree(list, 0L));
    }

    /**
     * 获取菜单树
     *
     * @param list 菜单列表
     * @param pid  父菜单id
     * @return 菜单树
     */
    private List<MenuRes.all> getTree(List<Menu> list, Long pid) {
        List<MenuRes.all> root = new ArrayList<>();
        list.forEach(Menu -> {
            if (!Objects.equals(Menu.getPid(), pid)) return;
            MenuRes.all item = ConvertUtil.copy(Menu, new MenuRes.all());
            root.add(item);
            List<MenuRes.all> tree = getTree(list, item.getId());
            item.setChildren(tree.isEmpty() ? null : tree);
        });
        return root;
    }

    /**
     * 保存菜单
     *
     * @param param 菜单请求参数
     * @return 保存结果
     */
    public Res<?> save(MenuReq.save param) {
        new Menu().where(Menu::getPath).eq(param.getPath())
                .oneOpt()
                .ifPresent(Menu -> {
                    if (!Menu.getId()
                            .equals(param.getId())) throw new CustomException("菜单路由地址已存在");
                });
        Menu menu = ConvertUtil.copy(param, new Menu());
        menu.saveOrUpdate();
        return Res.success();
    }

    /**
     * 删除菜单
     *
     * @param param 菜单请求参数
     * @return 删除结果
     */
    @Transactional(rollbackFor = Exception.class)
    public Res<?> del(MenuReq.del param) {
        new Menu().setId(param.getId()).removeById();
        List<Long> pids = List.of(param.getId());
        List<Long> ids = new ArrayList<>();
        // 递归删除子菜单
        addChildrenMenuIds(pids, ids);
        menuMapper.deleteBatchByIds(ids);
        return Res.success();
    }

    /**
     * 添加子菜单id
     *
     * @param pids 父菜单id列表
     * @param ids  菜单id列表
     */
    private void addChildrenMenuIds(List<Long> pids, List<Long> ids) {
        List<Long> childrenIds = QueryChain.of(Menu.class).select(Menu::getId).in(Menu::getPid, pids).listAs(Long.class);
        if (!childrenIds.isEmpty()) {
            addChildrenMenuIds(childrenIds, ids);
            ids.addAll(childrenIds);
        }
    }

    /**
     * 设置菜单排序
     *
     * @param param 菜单请求参数
     * @return 设置结果
     */
    @Transactional(rollbackFor = Exception.class)
    public Res<?> setSort(MenuReq.setSort param) {
        param.getList().forEach(MenuReq -> new Menu().setSort(MenuReq.getSort()).where(Menu::getId).eq(MenuReq.getId()).update());
        return Res.success();
    }
}

